﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace Flame.Dlr
{

    /// <summary>
    /// 1) il check del separatore in "ToText()" deve considerare anche la chiusura della cella
    /// 2) versione e Header devono essere separati e la versione un numero intero crescente
    /// 3) 
    /// </summary>
    public class ScriptException : Exception { }

    public static class CellManager
    {
        const string Header = "#!flame";
        const int Version = 0;
        const char SpecialChar = '-';
        const char SeparatorChar = '/';

      /*  public static void tryHeaderVersion(string text, string headerversion)
        {
            if (lines.Length > 1 && lines[0].Substring(0, Header.Length) == Header) i = 1;
        }*/

        public static string ToText(IEnumerable<ScriptBrute> scripts)
        {
            StringBuilder sb = new StringBuilder();
            string special = new String(SpecialChar, 1);
            bool specialFound = true;

            while (specialFound)
            {
                foreach (ScriptBrute cell in scripts)
                {
                    specialFound = cell.Code.Contains(Environment.NewLine + special);
                    if (specialFound) break;
                }
                special += SpecialChar;
            }

            sb.Append(Header + SeparatorChar + Version.ToString() + SeparatorChar + special);
            sb.Append(Environment.NewLine);

            //sb.Append(separator);
            //sb.Append(Environment.NewLine);

            foreach (ScriptBrute cell in scripts)
            {
                sb.Append(special + cell.Header);
                sb.Append(Environment.NewLine);
                sb.Append(cell.Code);
                sb.Append(Environment.NewLine);
            }
            return sb.ToString();
        }


        static bool match(string line, string separator)
        {
            return line.Length >= separator.Length && line.Substring(0, separator.Length) == separator;
        }

        public static IEnumerable<ScriptBrute> FromText(string[] lines, bool headerMandatory = false)
        {


            string separator = new String(SpecialChar, 2);

            //Regex r_firstmatch = new Regex(@"^(?<separator>[^\w]+)(?<language>(\w\;)+)$");

            int i = -1;
            if (lines.Length > 1 && lines[0].Length >= Header.Length && lines[0].Substring(0, Header.Length) == Header)
            {
                string[] infos = lines[0].Split(SeparatorChar);
                if (infos.Length < 2) throw new ScriptException();

                int _version_;
                //if (lines[0].Length < Header.Length + 2) throw new ScriptException();
                if (!int.TryParse(infos[1], out _version_)) throw new ScriptException();
                if(_version_ > Version) throw new ScriptException();
                if (infos.Length >= 3 && infos[2] != "")
                    separator = infos[2];
            }
            else if (headerMandatory)
                throw new ScriptException();

            List<ScriptBrute> scripts = new List<ScriptBrute>();
            
            int n = lines.Length;
            while (i < n - 1)
            {
                bool firstmatch;
                do
                {
                    i++;
                    firstmatch = match(lines[i], separator);
                }
                while (i < n - 1 && !firstmatch);



                if (firstmatch)
                {
                    string matchString = lines[i].Substring(separator.Length);
                    i++;
                    if (i >= n) throw new Exception("Bad Formatted file");

                   // Regex r_lastmatch = new Regex(@"^" + Regex.Escape(m_firstmatch.Groups["separator"].Value) + Regex.Escape(m_firstmatch.Groups["language"].Value) + "$");
                    StringBuilder sb = new StringBuilder();
                    bool m;

                    m = match(lines[i], separator);
                    if (!m)
                    {
                        sb.Append(lines[i]);

                        do
                        {
                            i++;
                            if (i < n) //throw new Exception("Bad Formatted file");
                            {
                                m = match(lines[i], separator);
                                if (!m)
                                {
                                    sb.Append(Environment.NewLine);
                                    sb.Append(lines[i]);
                                }
                            }
                        }
                        while (i < n && !m);
                    }
                    scripts.Add(new ScriptBrute() { Header = matchString, Code = sb.ToString() });

                    i--;

                }
            }


            return scripts;
        }


      /*  public static string CellsToFlame(List<Script> scripts)
        {
            IronPython.Runtime.List pycells = new IronPython.Runtime.List();
            foreach (var c in scripts)
            {
                IronPython.Runtime.PythonDictionary pycell = new IronPython.Runtime.PythonDictionary();
                pycell.Add("Code", c.Code);
                pycell.Add("Language", c.Language);
                pycells.Add(pycell);
            }

            IronPythonExec x = new IronPythonExec();
            x.AddVariable(new Variable() { Name = "x", Data = pycells });
            var r = x.Execute("str(x)");
            return r.Data.ToString();
        }

        public static List<Script> FlameToCells(string text)
        {
            List<Script> scripts = new List<Script>();
            IronPythonExec x = new IronPythonExec();

            AssemblyHelper.Apply(AssemblyHelper.CurrentFlameAssemblies, x);

            dynamic d = x.Execute(text);
            IronPython.Runtime.List pycells = d.Data;

            foreach (IronPython.Runtime.PythonDictionary pycell in pycells)
            {
                scripts.Add(new Script() { Code = (string)pycell.get("Code"), Language = (Languages)pycell.get("Language") });
            }
            return scripts;
        }*/
    }
}
